import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

public class Aplikace {
	static final int POCET_HOSPOD = 4000;
	/** Pole prekladist */
	static ArrayList<Prekladiste> prekladiste;
	/** Pole hospod */
	static ArrayList<Hospoda> hospody;
	/** Pivovar */
	static Pivovar pivovar;
	/** ID Pivovar */
	static final int ID_PIVOVAR = 4008;
	/** list ve kterem jsou (musi byt) vsechna vozidla */
	static ArrayList<Vozidlo> listVozidel = new ArrayList<Vozidlo>();
	/** list vsech kamionu */
	static ArrayList<Kamion> listKamionu = new ArrayList<Kamion>();
	/** List objednavek na 1 den, ktery se generuje v 0:00 */
	static ArrayList<Objednavka> listObjednavek = new ArrayList<Objednavka>();
	/** Pocet dnu simulace */
	static final int POCET_DNU = 7;
	/** Pocet kamionu pro rozvoz z pivovaru (64x100 + 8x75) */
	static final int POCET_KAMIONU = 72;
	/** Pocet prekladist */
	static final int POCET_PREKLADIST = 8;
	/** kapacita nakladniho vozu v sudech */
	static final int KAPACITA_NAKLADNI_VUZ = 30;
	/** kapacita cisterny v hektolitrech */
	static final int KAPACITA_CISTERNA = 50;
	/** Sledovana hospoda */
	static int sledovanaHospoda = 5;
	/** Sledovany kamion */
	static int sledovanaKamion = POCET_KAMIONU;

	static int den = 0;

	public static void nactiSvet() {
		/**
		 * Nacteni pivovaru
		 */
		pivovar = new Pivovar(4008, 250, 250);
		System.out.println("Pivovar nacten");

		/**
		 * Nacteni prekladist
		 */
		prekladiste = new ArrayList<Prekladiste>();
		prekladiste.add(new Prekladiste(4000, 125, 125));
		prekladiste.add(new Prekladiste(4001, 125, 250));
		prekladiste.add(new Prekladiste(4002, 125, 375));
		prekladiste.add(new Prekladiste(4003, 250, 375));
		prekladiste.add(new Prekladiste(4004, 375, 375));
		prekladiste.add(new Prekladiste(4005, 375, 250));
		prekladiste.add(new Prekladiste(4006, 375, 125));
		prekladiste.add(new Prekladiste(4007, 250, 125));
		System.out.println("Prekladiste nactena");
		/**
		 * Nacteni hospod
		 */
		try {
			hospody = new ArrayList<Hospoda>();
			BufferedReader br = new BufferedReader(new FileReader("out.txt"));
			String radka;
			String[] rozsekanaRadka;
			Hospoda novaHospoda;
			for (int i = 0; i < POCET_HOSPOD; i++) {
				radka = br.readLine();
				rozsekanaRadka = radka.split(";");
				novaHospoda = new Hospoda(Integer.parseInt(rozsekanaRadka[0]),
						Integer.parseInt(rozsekanaRadka[1]),
						Integer.parseInt(rozsekanaRadka[2]),
						Byte.parseByte(rozsekanaRadka[3]));
				hospody.add(novaHospoda);
			}

			br.close();
		} catch (IOException e) {
			System.out.println("Nacteni hospod selhalo");
			e.printStackTrace();
		}
		System.out.println("Hospody nacteny");
		/**
		 * Nacteni sousedu
		 */
		try {
			BufferedReader br = new BufferedReader(new FileReader("map.txt"));
			String radka;
			String[] rozsekanaRadka;
			int pocetSousedu;
			for (int i = 0; i < 4009; i++) {
				radka = br.readLine();
				if (radka == null)
					continue;
				rozsekanaRadka = radka.split(";");
				pocetSousedu = (rozsekanaRadka.length - 1) / 2;
				if (i < POCET_HOSPOD) {
					int id = 0;
					for (int j = 1; j < rozsekanaRadka.length; j = j + 2) {
						hospody.get(i).pridejSouseda(id,
								Integer.parseInt(rozsekanaRadka[j]),
								Double.parseDouble(rozsekanaRadka[j + 1]));
						id++;
					}
				} else if (i == 4008) {
					int id = 0;
					for (int j = 1; j < rozsekanaRadka.length; j = j + 2) {
						pivovar.pridejSouseda(id,
								Integer.parseInt(rozsekanaRadka[j]),
								Double.parseDouble(rozsekanaRadka[j + 1]));
						id++;
					}
				} else {
					int id = 0;
					for (int j = 1; j < rozsekanaRadka.length; j = j + 2) {
						prekladiste.get(i - POCET_HOSPOD).pridejSouseda(id,
								Integer.parseInt(rozsekanaRadka[j]),
								Double.parseDouble(rozsekanaRadka[j + 1]));
						id++;
					}
				}
			}
			br.close();
		} catch (IOException e) {
			System.out.println("Nacteni sousedu selhalo");
			e.printStackTrace();
		} catch (NullPointerException e) {
			e.printStackTrace();
		}
		System.out.println("Sousedi nacteni");
		/**
		 * Nacteni cest
		 */
		BufferedReader br;
		try {
			br = new BufferedReader(new FileReader("roads.txt"));
			String radka;
			String[] rozsekanaRadka;
			int[] novePoleCest;
			for (int i = 0; i < POCET_HOSPOD; i++) {
				radka = br.readLine();
				rozsekanaRadka = radka.split("; ");
				novePoleCest = new int[rozsekanaRadka.length - 1];
				for (int j = 0; j < novePoleCest.length; j++) {
					novePoleCest[j] = Integer.parseInt(rozsekanaRadka[j + 1]);
				}
				hospody.get(i).cestaDoPrekladiste = novePoleCest;
			}
			br.close();
		} catch (IOException e) {
			System.out.println("Nacteni cest selhalo");
			e.printStackTrace();
		}
		System.out.println("Cesty nacteny");
	}

	/**
	 * Vytvori nove vozidlo a priradi mu prvni ukol
	 * 
	 * @param objednavka
	 *            Objednavka, kterou bude vozidlo obsluhovat jako prvni
	 * @param idPrekladiste
	 *            prekladiste, ke kteremu bude vozidlo patrit
	 * @param idHospoda
	 *            hospoda, do ktere se bude dorucovat objednavka
	 * @param typZasobovani
	 *            typ zasobovani hospody
	 */
	static void noveVozidlo(Objednavka objednavka) {
		int idPrekladiste = objednavka.getIdPrekladiste();
		int idHospoda = objednavka.getIdHospody();
		int typZasobovani = hospody.get(idHospoda).getTypZasobovani();
		/** Vytvoreni noveho vozidla */
		Vozidlo vozidlo;
		if (typZasobovani == 1) {// tankove pivo
			vozidlo = new Cisterna(idPrekladiste);
			vozidlo.naplnCisternu(objednavka.getObjemPiva());
		} else {// sudy
			vozidlo = new NakladniVuz(idPrekladiste);
			vozidlo.nalozSudy(objednavka.getObjemPiva());
		}
		vozidlo.setIdPrekladiste(idPrekladiste);

		/** zadavani ukolu */
		Hospoda hospoda = hospody.get(idHospoda);
		int[] cestaDoPrekladiste = hospoda.getCestaDoPrekladiste();
		double delkaSilnice = 0;
		int predchoziLokace = idPrekladiste;

		Hospoda tempHospoda = null;
		for (int k = cestaDoPrekladiste.length - 2; k >= -1; k--) {
			// zjisteni delky cesty

			if (k == -1) {
				tempHospoda = hospoda;
			} else {
				tempHospoda = hospody.get(cestaDoPrekladiste[k]);
			}
			for (int l = 0; l < tempHospoda.getSousedi().size(); l++) {
				if (tempHospoda.getSousedi().get(l).getDoLokace() == predchoziLokace) {
					delkaSilnice = tempHospoda.getSousedi().get(l).getDelka();
				}
			}
			// zarazeni vozidla
			int objem = objednavka.getObjemPiva();
			vozidlo.jizda((int) delkaSilnice, objem, tempHospoda.getId());
			if (k != -1)
				predchoziLokace = cestaDoPrekladiste[k];

		}

		/** Vylozeni a jizda zpet */
		if (vozidlo instanceof NakladniVuz) {
			vozidlo.vylozSudy(objednavka.getObjemPiva(), tempHospoda.getId());
		} else {
			vozidlo.vypustCisternu(objednavka.getObjemPiva(),
					tempHospoda.getId());
		}

		/** Zarazeni vozidla */
		listVozidel.add(vozidlo);
	}

	static void den() {
		++den;
		int hodin = 24;
		for (int i = 0; i < hodin; i++) {
			System.out.println("	Cas: " + i + ":00");
			if (i == 0) {
				// ArrayList<Objednavka> pomListObjednavek = Objednavka
				// .generujObjednavky();
				// listObjednavek.clear();
				// for (int j = 0; j < pomListObjednavek.size(); j++) {
				// listObjednavek.add(pomListObjednavek.remove(i));
				// }
				// listObjednavek.addAll(pomListObjednavek);
				listObjednavek.addAll(Objednavka.generujObjednavky());
				pivovar.vyrobaPiva();

				/** Rozvoz piva z pivovaru */
				if (listKamionu.isEmpty()) {
					for (int j = 0; j < POCET_KAMIONU; j++) {
						listKamionu.add(new Kamion(ID_PIVOVAR));
					}
					listVozidel.addAll(listKamionu);
				}

				int kamionCounter = 0;
				for (int j = 0; j < POCET_PREKLADIST; j++) {
					int delkaSilnice = 125;
					if (j % 2 == 0)
						delkaSilnice = 177;
					// 8 - pocet plnych kamionu (875 sudu - 8x100 + 1x75)
					for (int k = 0; k < 8; k++) {
						Kamion tempKamion = listKamionu.get(kamionCounter++);
						tempKamion.nalozSudy(100);
						tempKamion.jizda(delkaSilnice, 100, j + POCET_HOSPOD);
						tempKamion.vylozSudy(100, j + POCET_HOSPOD);
						tempKamion.jizda(delkaSilnice, 0, ID_PIVOVAR);
					}
					Kamion tempKamion = listKamionu.get(kamionCounter++);
					tempKamion.nalozSudy(75);
					tempKamion.jizda(delkaSilnice, 75, j + POCET_HOSPOD);
					tempKamion.vylozSudy(75, j + POCET_HOSPOD);
					tempKamion.jizda(delkaSilnice, 0, ID_PIVOVAR);
				}
				//

			}
			if (i >= 8 && i <= 16) {
				for (int j = 0; j < listObjednavek.size(); j++) {
					if (listObjednavek.get(j).getHodina() == i) {

						Objednavka objednavka = listObjednavek.get(j);
						int idPrekladiste = objednavka.getIdPrekladiste();
						int idHospoda = objednavka.getIdHospody();
						int typZasobovani = hospody.get(idHospoda)
								.getTypZasobovani();

						ArrayList<Vozidlo> tempListVozidel = new ArrayList<Vozidlo>();
						/** Vyber vozidel, ktere se nachazeji v prekladisti */
						for (int k = 0; k < listVozidel.size(); k++) {
							if (listVozidel.get(k).getPozice() == idPrekladiste)
								tempListVozidel.add(listVozidel.get(k));
						}
						if (tempListVozidel.size() == 0) {
							noveVozidlo(objednavka);

						} else {
							/**
							 * Zkoumame, jestli existujici vozidlo sdili nasi
							 * cestu a jestli neni plne
							 */

							// cilova hospoda
							Hospoda hospoda = hospody.get(idHospoda);
							int[] cestaDoPrekladiste = hospoda
									.getCestaDoPrekladiste();
							boolean objednavkaPridelena = false;

							for (int k = 0; k < tempListVozidel.size(); k++) {
								Vozidlo tempVozidlo = tempListVozidel.get(k);
								Queue<Ukol> ukoly = tempVozidlo.getUkoly();
								int pozice = tempVozidlo.getIdPrekladiste();
								if (!ukoly.isEmpty()) {
									Ukol ukol = ukoly.peek();
									pozice = ukol.pozice;
									if (tempVozidlo instanceof NakladniVuz) {
										if (tempVozidlo.getNaklad()
												+ objednavka.getObjemPiva() > KAPACITA_NAKLADNI_VUZ
												|| typZasobovani == 1) {
											continue;
										}
									} else {
										if (tempVozidlo.getNaklad()
												+ objednavka.getObjemPiva() > KAPACITA_CISTERNA
												|| typZasobovani == 0) {
											continue;
										}
									}

								}

								for (int l = 0; l < cestaDoPrekladiste.length; l++) {
									if (cestaDoPrekladiste[l] == pozice) {

										int predchoziLokace = pozice;
										double delkaSilnice = 0;

										/** Pridavame ukoly */
										Hospoda tempHospoda = null;
										for (int m = l - 1; m >= -1; m--) {
											// zjisteni delky cesty

											if (m == -1) {
												tempHospoda = hospoda;
											} else {
												tempHospoda = hospody
														.get(cestaDoPrekladiste[m]);

											}

											for (int n = 0; n < tempHospoda
													.getSousedi().size(); n++) {
												if (tempHospoda.getSousedi()
														.get(n).getDoLokace() == predchoziLokace) {
													delkaSilnice = tempHospoda
															.getSousedi()
															.get(n).getDelka();
												}
											}

											int objem = objednavka
													.getObjemPiva();
											if (!objednavkaPridelena) {
												tempVozidlo.jizda(
														(int) delkaSilnice,
														objem,
														tempHospoda.getId());
											}
											if (m != -1)
												predchoziLokace = cestaDoPrekladiste[m];
										}
										if (!objednavkaPridelena) {
											// Vylozeni
											if (tempVozidlo instanceof NakladniVuz) {
												tempVozidlo
														.vylozSudy(
																objednavka
																		.getObjemPiva(),
																tempHospoda
																		.getId());

											} else {
												tempVozidlo
														.vypustCisternu(
																objednavka
																		.getObjemPiva(),
																tempHospoda
																		.getId());
											}

											// Nalozeni

											if (tempVozidlo instanceof NakladniVuz) {
												tempVozidlo
														.nalozSudy(objednavka
																.getObjemPiva());

											} else {
												tempVozidlo
														.naplnCisternu(objednavka
																.getObjemPiva());
											}
										}
										objednavkaPridelena = true;

									}

								}
							}
							/**
							 * Objednavka nemohla byt pridelena existujicimu
							 * vozidlu
							 */
							if (!objednavkaPridelena)
								noveVozidlo(objednavka);

						}

					}
				}
				/** jizda zpet */
				for (int j = POCET_KAMIONU; j < listVozidel.size(); j++) {
					Vozidlo tempVozidlo = listVozidel.get(j);
					Queue<Ukol> ukoly = tempVozidlo.getUkoly();
					Ukol ukol = null;
					if (ukoly.size() > 0)
						ukol = ((LinkedList<Ukol>) ukoly).get(ukoly.size() - 1);
					
						

					if (!ukoly.isEmpty()) {
						if (ukol.pozice != tempVozidlo.getIdPrekladiste())
							listVozidel.get(j).jizda(tempVozidlo.getCelkovaVzalenost(), 0,
									tempVozidlo.getIdPrekladiste());
					}

				}
			}

			Vozidlo.uplynutiHodiny();
		}
		listObjednavek.clear();
	}

	static void simulace() {
		for (int i = 0; i < POCET_DNU; i++) {
			System.out.println(i + ". den");
			den();
		}
	}

	public static void main(String[] args) {
		nactiSvet();
		System.out.println("---Svet nacten---");

		Menu menu = new Menu();
		simulace();
	}
}
